import * as THREE from 'three';
import * as d3 from 'd3';
//import { CSM } from 'three/examples/jsm/csm/CSM.js';

type ConfigType = {
    useCanvasHeightAndWidth: boolean,
}
export class ThreeRender {
    protected scene: THREE.Scene;
    protected camera: THREE.Camera;
    protected renderer: THREE.WebGLRenderer;
    protected clock: THREE.Clock;
    protected canvas: Element;
    protected projection = d3.geoMercator().center([104.0, 37.5]).scale(80).translate([0, 0]);
    private renderConfig = {
        useCanvasHeightAndWidth: false
    }

    constructor(canvas: Element, config: ConfigType) {
        this.canvas = canvas;
        this.renderConfig.useCanvasHeightAndWidth = config.useCanvasHeightAndWidth;
        const { height , width } = this.getHeightAndWidth();
        this.clock = new THREE.Clock();
        this.scene = new THREE.Scene();
        this.camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
        this.renderer = new THREE.WebGLRenderer({ canvas, antialias: true, alpha: true });
        this.init();
    }

    private init() {
        this.updateRenderer();
        this.onResize();

        // const csm = new CSM( {
        //     maxFar: 75,
        //     cascades: 4,
        //     mode: 'practical',
        //     parent: this.scene,
        //     shadowMapSize: 1024,
        //     lightDirection: new THREE.Vector3(20, -50,20 ).normalize(),
        //     camera: this.camera
        // });
    }

    protected getHeightAndWidth(fixHeight: number = 1080, fixWidth: number = 1920) {
        let height,width;
        if (this.renderConfig.useCanvasHeightAndWidth) {
            height = this.canvas.clientHeight;
            width = this.canvas.clientWidth;
        } else {
            height = window.innerHeight;
            width = window.innerWidth;
        }
        return {
            height,
            width,
            fixHeight,
            fixWidth
        }
    }

    protected updateRenderer() {
        this.checkRender(() => {
            const { height , width } = this.getHeightAndWidth();
            (this.camera as any).aspect = width / height;
            (this.camera as any).updateProjectionMatrix();
            this.renderer!.setSize(width, height);
            this.renderer!.setPixelRatio(window.devicePixelRatio);
        });
    }

    protected checkRender(callback: Function): void {
        this.renderer && this.scene && this.camera && callback();
    }

    protected onResize() {
        window.addEventListener('resize', this.updateRenderer.bind(this));
    }

    protected unResize() {
        window.removeEventListener('resize', this.updateRenderer.bind(this));
    }
}